import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
import { AnimationFrame, ITimer } from '../animation/animation-frame';
import { Helper } from '../tool/helper';
import { Quaternion, Vector3 } from '@babylonjs/core/Maths/math.vector';
import { Stage } from '../base/stage';


/**
 * 跟随容器
 */
abstract class FollowContainer {
    private _req: ITimer = {};
    private _resetThreshold = 0.3;
    private _refZ = new Vector3();
    private _dirF = new Vector3();
    private _dirT = new Vector3();
    private _rot = new Quaternion(0, 0, 0, 1);

    protected content: TransformNode;

    public readonly name: string;
    public readonly stage: Stage;
    public readonly container: TransformNode;

    constructor(name: string, stage: Stage) {
        this.name = name;
        this.stage = stage;
        this.container = new TransformNode('actor-container-node', stage.mainScene);
        this.container.rotationQuaternion = Quaternion.Identity();
        this.content = this.initializeContent();
        this.content.setParent(this.container);
        this.lock();
    }

    /**
     * 更新相机当前水平方向为参考方向
     */
    public updateReference(): void {
        const refZ = this._refZ;
        Helper.cameraDirection(this.stage.mainCamera, refZ);
        refZ.y = 0;
        refZ.normalize();
    }

    /**
     * 设置最大偏移角度（与参考方向的点积）
     * @param threshold 
     */
    public setThreshold(threshold: number): void {
        this._resetThreshold = threshold;
    }

    /**
     * 立即对齐
     */
    public align(): void {
        const camera = this.stage.mainCamera;
        this.container.position.copyFrom(camera.position);
        Helper.cameraDirection(camera, this._dirF);
        this._dirF.y = 0;
        this.container.getDirectionToRef(this._refZ, this._dirT);
        const dot = Vector3.Dot(this._dirF, this._dirT);
        this._dirF.normalize();
        Quaternion.FromUnitVectorsToRef(this._dirT, this._dirF, this._rot);
        this.container.rotationQuaternion!.multiplyInPlace(this._rot);
    }

    /**
     * 初始化容器内容
     */
    protected abstract initializeContent(): TransformNode;

    private lock(): void {
        const stage = this.stage;
        const container = this.container;
        const dirF = this._dirF;
        const dirT = this._dirT;
        const rot = this._rot;
        this._req.observable = stage.mainScene.onBeforeRenderObservable;
        const refZ = this._refZ;
        Helper.cameraDirection(stage.mainCamera, refZ);
        refZ.y = 0;
        refZ.normalize();
        AnimationFrame.request(() => {
            const camera = stage.mainCamera;
            container.position.copyFrom(camera.position);
            Helper.cameraDirection(camera, dirF);
            dirF.y = 0;
            container.getDirectionToRef(refZ, dirT);
            const dot = Vector3.Dot(dirF, dirT);
            if (dot < this._resetThreshold) {
                dirF.normalize();
                Quaternion.FromUnitVectorsToRef(dirT, dirF, rot);
                container.rotationQuaternion!.multiplyInPlace(rot);
            }
        }, 1, 200, this._req);
    }

}


export { FollowContainer };